home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 23 / CU Amiga - Super CD-ROM 23 (June 1998).iso / CreatingGames / GameCreators / Inform / examples / Balances.inf < prev    next >
Encoding:
Text File  |  1997-03-15  |  73.8 KB  |  1,922 lines

  1. ! ----------------------------------------------------------------------------
  2. !   Balances 961216                 One of the standard Inform 6 example games
  3. !
  4. !                                                             created: 25.9.94
  5. !                                                             updated: 6.10.94
  6. !                                                         modernised: 11.12.95
  7. !                                               translated to Inform 6: 8.5.96
  8. !                                                   minor bugs fixed: 16.12.96
  9. !
  10. !   This short story was written to demonstrate large-scale programming of
  11. !   the parser, and features multiple objects, complicated plurals, variable
  12. !   verbs, objects named by the player and questions.  The spell-casting
  13. !   system is written in a "safe" way so that it could easily be transplanted.
  14. !
  15. !   Needs Inform 6, library 6/1 or later to compile.
  16. ! ----------------------------------------------------------------------------
  17.  
  18. Release 5;
  19. Serial "961216";
  20. Switches d;
  21.  
  22. Constant Story "BALANCES";
  23. Constant Headline "^An Interactive Short Story
  24.                    ^Copyright (c) 1994, 1995, 1996 by Graham Nelson.^";
  25.  
  26. Constant OBJECT_SCORE 5;
  27. Constant MAX_SCORE 51;
  28.  
  29. Include "Parser";
  30. Include "VerbLib";
  31.  
  32. ! ----------------------------------------------------------------------------
  33. !   The white featureless cubes from "Spellbreaker", which can be identified
  34. !   by being written on with the magic burin, so that their names are given
  35. !   by the player in the course of play
  36. !
  37. !   A particularly witty thing to do is to give several of them the same name,
  38. !   or to frotz some of them to distinguish them from the others...
  39. !   And the game will have no problem with this.
  40. ! ----------------------------------------------------------------------------
  41.  
  42. Array cube_text_buffer -> 8;
  43. Global the_named_word = 0;
  44. Global from_char; Global to_char;
  45.  
  46. Class  FeaturelessCube
  47.   with number 0 0 0 0,   ! There's room for 8 bytes of text in these 4 entries
  48.        description "A perfect white cube, four inches on a side.",
  49.        parse_name
  50.        [ i j flag;
  51.             if (parser_action==##TheSame)
  52.             {   for (i=0:i<8:i++)
  53.                     if ((parser_one.&number)->i
  54.                         ~= (parser_two.&number)->i) return -2;
  55.                 return -1;
  56.             }
  57.             for (::i++)
  58.             {   j=NextWord(); flag=0;
  59.                 if (j=='cube' or 'white' ||
  60.                     (j=='featureless' or 'blank' &&
  61.                            ((self.&number)->0) == 0)) flag=1;
  62.                 if (j=='cubes')
  63.                 {   flag=1; parser_action=##PluralFound; }
  64.                 if (flag==0 && ((self.&number)->0) ~= 0)
  65.                 {   wn--;
  66.                     if (TextReader(0)==0) return i;
  67.                     for (j=0: j<8: j++)
  68.                         if ((self.&number)->j ~= cube_text_buffer->j)
  69.                             return i;
  70.                     flag=1;
  71.                 }
  72.                 if (flag==0) return i;
  73.             }
  74.        ],
  75.        article "a",
  76.        short_name
  77.        [ i; if (((self.&number)->0) == 0) print "featureless white cube";
  78.             else
  79.             {   print "~";
  80.                 while (((self.&number)->i) ~= 0)
  81.                     print (char) (self.&number)->i++;
  82.                 print "~ cube";
  83.             }
  84.             rtrue;
  85.        ],
  86.        plural
  87.        [;   self.short_name(); print "s";
  88.        ],
  89.        baptise
  90.        [ i; wn = the_named_word;
  91.             if (TextReader(1)==0) return i;
  92.             for (i=0: i<8: i++)
  93.                 (self.&number)->i = cube_text_buffer->i;
  94.             self.article="the";
  95.             print_ret "It is now called ", (the) self, ".";
  96.        ],
  97.   has  scored;
  98.  
  99. !  Copies word "wn" from what the player most recently typed, putting it as
  100. !  plain text into cube_text_buffer, returning false if no such word is there
  101.  
  102. [ TextReader flag point i j len;
  103.  
  104.    if (flag==1 && from_char~=to_char)
  105.    {   for (i=from_char, j=0:i<=to_char && j<7:i++)
  106.        {   cube_text_buffer->j = buffer->i;
  107.            if (buffer->i ~= ' ' or ',' or '.') j++;
  108.        }
  109.        for (:j<8:j++) cube_text_buffer->j = 0;
  110.        from_char=0; to_char=0;
  111.        rtrue;
  112.    }
  113.  
  114.    for (i=0:i<8:i++) cube_text_buffer->i = 0;
  115.    if (wn > parse->1) { wn++; rfalse; }
  116.    i=wn*4+1; j=parse->i; point=j+buffer; len=parse->(i-1);
  117.  
  118.    for (i=0:i<len && i<7:i++) cube_text_buffer->i = point->i;
  119.  
  120.    wn++; rtrue;
  121. ];
  122.  
  123. Object burin "magic burin"
  124.   with name "magic" "magical" "burin" "pen",
  125.        description
  126.           "This is a magical burin, used for inscribing objects with words
  127.            or runes of magical import. Such a burin also gives you the
  128.            ability to write spell scrolls.",
  129.        before
  130.        [; WriteOn:
  131.              if (second ofclass FeaturelessCube)
  132.              {   if (second notin player)
  133.                      "Writing on a cube is such a fiddly process that you
  134.                       need to be holding it in your hand first.";
  135.                  if (burin notin player)
  136.                      "You would need some powerful implement for that.";
  137.                  second.baptise();
  138.                  rtrue;
  139.              }
  140.              if (second ofclass SpellBook)
  141.                  "If a burin could write in a spell book, you wouldn't need
  142.                   the gnusto spell!";
  143.              if (second ofclass Scroll)
  144.                  "You cannot write just anything on the magic parchment of
  145.                   a scroll: you can only ~copy~ a spell to it.";
  146.        ];
  147.  
  148. [ WriteOnSub; "Graffiti is banned."; ];
  149.  
  150. [ CopyToSub;
  151.   if (burin notin player) "You need to be holding the burin to copy a spell.";
  152.   if (second ofclass SpellBook)
  153.       "If a burin could write in a spell book, you wouldn't need
  154.        the gnusto spell!";
  155.   if (~~(second ofclass Scroll)) "You can only copy spells to scrolls.";
  156.   if (child(second)~=0)
  157.       "The scroll is already full of incantation.";
  158.   "The scroll is not blank, only illegible.";
  159. ];
  160.  
  161. ! ----------------------------------------------------------------------------
  162. !   Now the whole spell-casting system
  163. ! ----------------------------------------------------------------------------
  164.  
  165. Attribute known_about;                 ! Player has seen this spell somewhere
  166. Attribute reversed;                    ! Effect of this known spell reversed
  167.  
  168. Attribute is_spell;
  169. Class  Spell
  170.   with name "spell" "spells", article "the",
  171.        number 0,
  172.        word_name
  173.        [;  print (address) (self.&name)-->0;
  174.        ],
  175.        short_name
  176.        [;  self.word_name(); print " spell"; give self known_about; rtrue;
  177.        ],
  178.        specification
  179.        [;  self.short_name();
  180.            print ": ", (string) self.purpose;
  181.        ],
  182.        before
  183.        [;  Examine: self.specification(); ".";
  184.        ],
  185.   has  is_spell;
  186.  
  187. Object memory
  188.   with capacity 5,
  189.        number_known 1,
  190.        describe_contents
  191.        [ i j k;
  192.            objectloop (i in self) if (i.number==100) j++;
  193.            if (j>0)
  194.            {   print "The ";
  195.                objectloop (i in self)
  196.                    if (i.number==100)
  197.                    {   k++; i.word_name();
  198.                        if (k==j-1) print " and ";
  199.                        if (k<j-1) print ", ";
  200.                    }
  201.                if (j==1) print " spell is"; else print " spells are";
  202.                print " yours forever.  Other than that, y";
  203.            }
  204.            else print "Y";
  205.            print "ou have ";
  206.            j=0; k=0;
  207.            objectloop (i in self) if (i.number<100) j++;
  208.            if (j>0)
  209.            {   print "the ";
  210.                objectloop (i in self)
  211.                    if (i.number<100)
  212.                    {   k++;
  213.                        print (name) i;
  214.                        if (i.number==2) print " (twice)";
  215.                        if (i.number==3) print " (thrice)";
  216.                        if (i.number==4) print " (four times)";
  217.                        if (i.number>=5) print " (many times)";
  218.                        if (k==j-1) print " and ";
  219.                        if (k<j-1) print ", ";
  220.                    }
  221.            }
  222.            else print "no spells";
  223.            " memorised.";
  224.        ],
  225.        learn_spell
  226.        [ sp;
  227.            if (sp.number==100) "You always know that spell.";
  228.            print "Using your best study habits, you commit the ";
  229.            sp.word_name();
  230.            print " spell to memory";
  231.            if (sp notin self) sp.number=0;
  232.            move sp to self;
  233.            self.number_known++;
  234.            sp.number++;
  235.            if (sp.number==1) print ".";
  236.            if (sp.number==2) print " once again.";
  237.            if (sp.number==3) print " a third time.";
  238.            if (sp.number>3) print " yet another time.";
  239.            if (self.number_known <= self.capacity) { new_line; rtrue; }
  240.            self.forget_spell(sibling(child(self)));
  241.            "  You have so much buzzing around in your head, though,
  242.               that it's likely something may have been forgotten
  243.               in the shuffle.";
  244.        ],
  245.        forget_spell
  246.        [ sp;
  247.            if (sp notin self || sp.number==100) rtrue;
  248.            self.number_known--;
  249.            sp.number--;
  250.            if (sp.number==0) remove sp;
  251.            rtrue;
  252.        ];
  253.  
  254. Spell -> gnusto_spell
  255.   with name "gnusto",
  256.        purpose "copy a scroll into your spell book",
  257.        number 100,
  258.        magic
  259.        [ i a_book;
  260.             if (second ofclass SpellBook)
  261.                "Unlike scrolls, spell books are magically guarded against
  262.                 the 'theft' of their lore.";
  263.             if (second==0 || ~~(second ofclass Scroll))
  264.                "Your spell fizzles vaguely out.";
  265.             if (second notin player)
  266.                 "A gnusto spell would require close scrutiny of the scroll
  267.                  it is to copy: which you do not seem to be holding.";
  268.             objectloop (i in player)
  269.                 if (i ofclass SpellBook) a_book=i;
  270.             if (a_book==0)
  271.                 "Your spell fails, as you have no spell book.";
  272.             i=child(second);
  273.             if (i==0 || ~~(i ofclass Spell))
  274.             {   print_ret "Your spell fails, as ", (the) second,
  275.                    " is illegible.";
  276.             }
  277.             a_book.learn_spell(i); remove second;
  278.             print_ret
  279.                "Your spell book begins to glow softly.  Slowly, ornately,
  280.                 the words of ", (the) i, " are inscribed,
  281.                 glowing even more brightly then the book itself. 
  282.                 The book's brightness fades, but the spell remains! 
  283.                 However, the scroll on which it was written vanishes as
  284.                 the last word is copied.";
  285.        ];
  286.  
  287. Class SpellBook
  288.   with array_of_spells 0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0,
  289.        capacity 16,
  290.        learn_spell
  291.        [ sp p i;
  292.               p = self.&array_of_spells;
  293.               for (i=0:i<self.capacity && (p-->i)~=0:i++) ;
  294.               if (i==self.capacity) rtrue;
  295.               p-->i = sp;
  296.        ],
  297.        before
  298.        [; Open, Close:
  299.               print_ret
  300.               (The) self, " is always open to the right place, but it
  301.               is also always closed. This eliminates tedious leafing and
  302.               hunting for spells.  Many lives have been saved by this
  303.               magical innovation.";
  304.           Attack:
  305.               print_ret "When you are done, ", (the) self, " remains unmarred.";
  306.        ],
  307.        after
  308.        [ p i j; Examine:
  309.               p = self.&array_of_spells;
  310.               for (i=0:i<self.capacity && (p-->i)~=0:i++)
  311.               {   j=p-->i; <Examine j>;
  312.               }
  313.               rtrue;
  314.        ];
  315.  
  316. Class Scroll
  317.   with parse_name
  318.        [ i j k; j=-1;
  319.               if (self has general)
  320.               {   if (child(self)~=0 && child(self) ofclass Spell)
  321.                       j=(child(self).&name)-->0; else j='illegible';
  322.               }
  323.               for (::)
  324.               {   k=NextWord();
  325.                   if (k=='scrolls') parser_action=##PluralFound;
  326.                   if ((k=='scrolls' or 'scroll' or j) || k==(self.&name)-->0)
  327.                       i++;
  328.                   else return i;
  329.               }
  330.        ],
  331.        before
  332.        [ i; Examine:
  333.             i=child(self);
  334.             give self general;
  335.             if (i==0 || ~~(i ofclass Spell))
  336.                 "The scroll has faded, and you cannot read it.";
  337.             print "The scroll reads ~"; i.specification(); "~.";
  338.        ],
  339.        invent
  340.        [;   if (inventory_stage==2 && self has general)
  341.             {   if (child(self)==0 || ~~(child(self) ofclass Spell))
  342.                     print " (which is illegible)";
  343.                 else
  344.                 {   print " (of ", (the) child(self), ")"; }
  345.             }
  346.        ];
  347.  
  348. [ ReadableSpell i j k;
  349.   if (scope_stage==1)
  350.   {   if (action_to_be==##Examine) rfalse;
  351.       rtrue;
  352.   }
  353.   if (scope_stage==2)
  354.   {   objectloop (i in player)
  355.           if (i ofclass SpellBook)
  356.           {   for (k=0:k<i.capacity && (i.&array_of_spells)-->k~=0:k++)
  357.               {   j=(i.&array_of_spells)-->k; PlaceInScope(j);
  358.               }
  359.           }
  360.       rtrue;
  361.   }
  362.   ! No need for scope_stage 3 (the error stage), because our
  363.   ! ParserError routine handles that case instead
  364. ];
  365.  
  366. [ CopyableSpell i j k;
  367.   if (scope_stage==1) return 1;
  368.   if (scope_stage==2)
  369.   {   objectloop (i in player)
  370.           if (i ofclass SpellBook)
  371.           {   for (k=0:k<i.capacity && (i.&array_of_spells)-->k~=0:k++)
  372.               {   j=(i.&array_of_spells)-->k; PlaceInScope(j);
  373.               }
  374.           }
  375.       rfalse;
  376.   }
  377.   ! No need for scope_stage 3 (the error stage), because our
  378.   ! ParserError routine handles that case instead
  379. ];
  380.  
  381. [ SpellsSub; memory.describe_contents(); ];
  382.  
  383. [ LearnSub; if (location==thedark)
  384.                 print "(The magic writing of the spells casts enough light
  385.                         that you can read them.)^";
  386.             memory.learn_spell(noun);
  387. ];
  388.  
  389. Global the_spell_was = gnusto_spell;
  390.  
  391. [ CastOneSub; <Cast the_spell_was noun>; ];
  392.  
  393. [ CastSub;
  394.   the_spell_was = noun; memory.forget_spell(noun);
  395.  
  396.   if (noun has reversed)
  397.   {   give noun ~reversed;
  398.       if (noun.unmagic() ~= 0) return;
  399.       "Nothing happens.";
  400.   }
  401.  
  402.   if (second ~= 0)
  403.   {   ResetVagueWords(second);                     ! Set "it", "him", "her"
  404.       if (second provides before
  405.           && second.before() ~= 0) return;         ! Run before routine(s)
  406.   }
  407.   if (noun.magic() ~= 0) return;
  408.   "Nothing happens.";
  409. ];
  410.  
  411. [ InScope i;
  412.   if (verb_word=='c,cast' or 'cast')
  413.       objectloop (i in memory) PlaceInScope(i);
  414.   rfalse;
  415. ];
  416.  
  417. [ ParserError x i flag vb;
  418.   if (etype==VERB_PE or ASKSCOPE_PE)
  419.   {   if (etype==ASKSCOPE_PE)
  420.       {   if (verb_word=='cast') vb=1;
  421.           if (verb_word=='learn' or 'memorise' or 'memorize') vb=2;
  422.           if (verb_word=='copy') vb=3;
  423.           if (vb==0) { etype=CANTSEE_PE; rfalse; }
  424.       }
  425.       wn=verb_wordnum; if (vb~=0) wn++;
  426.       x=NextWordStopped();
  427.       for (i=player+1:i<=top_object:i++)
  428.           if (i ofclass Spell && Refers(i,x)==1
  429.               && i has known_about) flag=1;
  430.       if (flag==1)
  431.       {   if (vb==0 or 1)
  432.              "You haven't got that spell committed to memory.  [Type ~spells~
  433.               to see what you do remember.]";
  434.           if (vb==2)
  435.              "Your training is such that you can only memorise such a spell
  436.               with the aid of a spell book containing it.";
  437.           if (vb==3)
  438.              "You have no text of that spell to copy.";
  439.       }
  440.       if (vb==1)
  441.          "You haven't learned that spell, if indeed it is a spell.";
  442.       if (vb==2 or 3)
  443.          "You haven't access to that spell, if indeed it is a spell.";
  444.   }
  445.   rfalse;
  446. ];
  447.  
  448. [ ChooseObjects obj code;
  449.   if (code<2) rfalse;
  450.   if (action_to_be==##WriteOn && obj in player) return 9;
  451.   return 0;
  452. ];
  453.  
  454. [ UnknownVerb word i;
  455.   objectloop (i in memory)
  456.       if (word==(i.&name)-->0) { the_spell_was = i; return 'c,cast'; }
  457.   rfalse;
  458. ];
  459.  
  460. [ PrintVerb v;
  461.   if (v=='c,cast') { print "cast a spell at"; rtrue; }
  462.   rfalse;
  463. ];
  464.  
  465. ! ----------------------------------------------------------------------------
  466. !   And now, on with the story.  First, some global variables:
  467. ! ----------------------------------------------------------------------------
  468.  
  469. Global prepared_flag = false;      !  Prepared for resurrection?
  470. Global hearing_good  = false;      !  Sharp hearing?
  471. Global number_filled = 0;          !  Sockets in the temple filled
  472.  
  473. ! ----------------------------------------------------------------------------
  474. !   A "questions" verb.  Thus,
  475. !      "who is my friend helistar"
  476. !      "what was the great change"
  477. !   and so on are recognised.
  478. ! ----------------------------------------------------------------------------
  479.  
  480. [ QuerySub;
  481.   noun.description();
  482. ];
  483. [ Topic i;
  484.   if (scope_stage==1) return 0;
  485.   if (scope_stage==2)
  486.   {   objectloop (i ofclass Question) PlaceInScope(i);
  487.       rtrue;
  488.   }
  489.   "At the moment, even the simplest questions confuse you.";
  490. ];
  491.  
  492. Class Question;
  493. Question
  494.   with name "helistar" "my" "friend" "colleague",
  495.        description
  496.       "Helistar is your colleague, an Enchanter like you who has been much
  497.        on your mind lately.  She has been investigating some very dark
  498.        magic indeed, and seems not to be around any more.  You feel rather
  499.        vague about the details.";
  500. Question
  501.   with name "magical" "magic" "burin",
  502.        description "A burin is an engraving and writing tool.";
  503. Question
  504.   with name "change" "great",
  505.        description
  506.       "Something you had a lot to do with, but what exactly?  No, it's gone.";
  507. Question
  508.   with name "cyclops",
  509.        description
  510.       "A one-eyed giant, usually hostile.  (Don't they teach anything at
  511.        adventurer school these days?)";
  512. Question
  513.   with name "grue",
  514.        description
  515.       "The grue is a sinister, lurking presence in the dark places of the
  516.        earth. Its favorite diet is adventurers, but its insatiable appetite
  517.        is tempered by its fear of light. No grue has ever been seen by the
  518.        light of day, and few have survived its fearsome jaws to
  519.        tell the tale.";
  520. Question
  521.   with name "grimoire",
  522.        description
  523.       "According to Chambers English Dictionary, a grimoire is ~a magician's
  524.        book for calling up spirits~.";
  525. Question
  526.   with name "spells" "work",
  527.        description
  528.       "Your memory is still dream-hazed, but it's coming back. As a trained
  529.        Enchanter, you have the ability to cast spells like ~frotz~, provided
  530.        you have learned them in advance.  Some of these spells can be cast
  531.        at something; others can be cast alone.
  532.      ^^Spells are very complicated.  Each time you cast one, you forget it
  533.        (though you can get around this by learning it several times, so as
  534.        to have several uses up your sleeve).  The only way to hang on to
  535.        a spell is to have it written down, on a scroll or in a spell book.
  536.        Scrolls are not ideal for this, and you can only learn a spell from
  537.        your spell book.  (But you can add spells to your book.)
  538.      ^^[Type ~learn frotz~ and then ~frotz coin~ for an example.  You can
  539.        also type ~spells~ to see what you currently have memorised.]";
  540.  
  541. ! ----------------------------------------------------------------------------
  542. !   Some multiple objects, coins in fact, coded in deluxe fashion:
  543. ! ----------------------------------------------------------------------------
  544.  
  545. Attribute is_coin;
  546. Class Coin
  547.   with name "coin",
  548.        description "A round unstamped disc, presumably part of the local
  549.            currency.",
  550.        parse_name
  551.        [ i j w;
  552.          if (parser_action==##TheSame)
  553.          {   if ((parser_one.&name)-->0 == (parser_two.&name)-->0) return -1;
  554.              return -2;
  555.          }
  556.          w=(self.&name)-->0;
  557.          for (::i++)
  558.          {   j=NextWord();
  559.              if (j=='coins') parser_action=##PluralFound;
  560.              else if (j~='coin' or w) return i;
  561.          }
  562.        ],
  563.   has  is_coin;
  564.  
  565. Class GoldCoin
  566.  class Coin,
  567.   with name "gold",
  568.        short_name "gold coin",
  569.        plural "gold coins";
  570. Class SilverCoin
  571.  class Coin,
  572.   with name "silver",
  573.        short_name "silver coin",
  574.        plural "silver coins";
  575. Class BronzeCoin
  576.  class Coin,
  577.   with name "bronze",
  578.        short_name "bronze coin",
  579.        plural "bronze coins";
  580.  
  581. SilverCoin players_coin;
  582.  
  583. [ TossCoinSub; if (noun notin player) "You need to be holding the coin first.";
  584.   move noun to parent(player);
  585.   if (location==thedark) "You throw it away into the darkness.";
  586.   if (random(20)==1)
  587.      "You toss the coin, and it lands... on its edge, amazingly.";
  588.   "You toss the coin, and it comes up... blank, since neither side is
  589.    marked.";
  590. ];
  591.  
  592. ! ----------------------------------------------------------------------------
  593. !   The player's spell book, and three initial spells (to go with gnusto):
  594. ! ----------------------------------------------------------------------------
  595.  
  596. SpellBook players_book "spell book"
  597.   with name "spell" "book" "my" "spellbook",
  598.        description "My Spell Book^";
  599.  
  600. Spell frotz_spell
  601.   with name "frotz",
  602.        purpose "cause an object to give off light",
  603.        magic
  604.        [;  if (second==0) "There is a brief, blinding flash of light.";
  605.            if (second has animate)
  606.                "The spell, not designed for living creatures, goes sour.";
  607.            if (second in compass)
  608.                "The spell dissipates vaguely.";
  609.            give second light;
  610.            print_ret
  611.             "There is an almost blinding flash of light as ", (the) second,
  612.             " begins to glow!  It slowly fades to a less painful level, but ",
  613.             (the) second, " is now quite usable as a light source.";
  614.        ],
  615.        unmagic
  616.        [;  if (second==0) "There is a brief moment of deep darkness.";
  617.            if (second has animate)
  618.                "The spell, not designed for living creatures, goes sour.";
  619.            if (second in compass)
  620.                "The spell dissipates vaguely.";
  621.            if (second hasnt light)
  622.                print_ret (The) second, " isn't producing light as it is.";
  623.            give second ~light;
  624.            print_ret "A pool of darkness coagulates around ", (the) second,
  625.                  " but slowly fades back to normality.  Still, ",
  626.                  (the) second, " is no longer any kind of light source.";
  627.        ];
  628.  
  629. Spell rezrov_spell
  630.   with name "rezrov",
  631.        purpose "open even locked or enchanted objects",
  632.        magic
  633.        [;  if (second==0) "The world is open already.";
  634.            if (second has animate)
  635.                "It might be a boon to surgeons if it worked, but it doesn't.";
  636.            if (second has open || second hasnt openable)
  637.                "It doesn't need opening.";
  638.            if (second hasnt locked)
  639.            {   give second open;
  640.                print_ret (The) second, " opens obediently. 
  641.                Like swatting a fly with a sledge hammer, if you ask me.";
  642.            }
  643.            give second open ~locked;
  644.            print "Silently, ", (the) second, " swings open. ";
  645.            if (second has container) <<Search second>>; new_line; rtrue;
  646.        ],
  647.        unmagic
  648.        [;  if (second==0) "The world is closed already.";
  649.            if (second has animate)
  650.                "Happily, that is unnecessary.";
  651.            if (second has locked || second hasnt lockable)
  652.                "It doesn't need locking.";
  653.            give second ~open locked;
  654.            "Silently, ", (the) second, " swings shut and locks.";
  655.        ];
  656.  
  657. Spell yomin_spell
  658.   with name "yomin",
  659.        purpose "mind probe",
  660.        magic
  661.        [;  if (second==0 || second hasnt animate)
  662.                "That must be either vegetable or mineral.";
  663.            if (second==player) "You give yourself a mild headache.";
  664.            print_ret "You look into the rather ordinary thoughts of ",
  665.                      (the) second, ".";
  666.        ],
  667.        unmagic
  668.        [;  if (second==0 || second hasnt animate)
  669.                "That must be either vegetable or mineral.";
  670.            if (second==player) "You give yourself a mild headache.";
  671.            print_ret (The) second, " is rather shocked, for some reason.";
  672.        ];
  673.  
  674. ! ----------------------------------------------------------------------------
  675. !   The first scene: the Hut and its (rather easy) secret 
  676. ! ----------------------------------------------------------------------------
  677.  
  678. Class Place
  679.   has  light;
  680.  
  681. Place Hut "Ramshackle Hut"
  682.   with description
  683.           "Until quite recently, someone lived here, you feel sure. 
  684.            Now the furniture is matchwood and
  685.            the windows are glassless.  Outside, it is a warm, sunny day,
  686.            and grasslands extend to the low hills on the horizon.",
  687.        out_to Grasslands, w_to Grasslands,
  688.        cant_go "There's only the one room: better go ~out~.",
  689.        name "windows" "grasslands" "grass" "hills";
  690.  
  691. Object -> furniture "wooden furniture"
  692.   with name "furniture" "broken" "wood" "wooden",
  693.        before
  694.        [;  Examine, Search, LookUnder:
  695.                self.before=0; score=score+5;
  696.                move h_box to player;
  697.                "Searching through the furniture, which is good for nothing
  698.                 but firewood now, you come across an old cedarwood box,
  699.                 which you pick up for a closer look.";
  700.        ],
  701.   has  scenery;
  702.  
  703. Object h_box "cedarwood box"
  704.   with name "cedar" "cedarwood" "wooden" "box",
  705.        description "The box bears the calligraphed initial H."
  706.   has  container openable lockable locked;
  707.  
  708. SpellBook -> helistars_book "Helistar's grimoire"
  709.   with name "grimoire" "helistar" "helistars",
  710.        description "This must be the grimoire of dangerous spells kept by
  711.                     your irresponsible friend Helistar.  Many pages are
  712.                     missing, but a few spells remain:^",
  713.   has  proper;
  714.  
  715. ! ----------------------------------------------------------------------------
  716. !   Grasslands and the valley
  717. ! ----------------------------------------------------------------------------
  718.  
  719. Place Grasslands "Grasslands, near Hut"
  720.   with name "grasslands" "grass" "hut" "path",
  721.        description
  722.           "The grasslands sway over low hills in all directions: it is a
  723.            peaceful wilderness, broken only by this hut and a faint path
  724.            to the north.",
  725.        in_to Hut, e_to Hut,
  726.        n_to Valley,
  727.        cant_go "You wander around for a while but end up back at the hut.";
  728.  
  729. Place Valley "Pocket Valley"
  730.   with name "valley" "trail",
  731.        description
  732.           "A pleasant pocket valley in the grassy hills, through which a
  733.            trail runs north-to-south.",
  734.        n_to "The trail runs out to nothing, and you retreat for fear of
  735.              getting so lost you couldn't find the hut again by nightfall.",
  736.        cant_go "You wander around the pleasant valley, but are afraid to
  737.                 lose sight of the trail.",
  738.        s_to Grasslands;
  739.  
  740. [ RideSub; print_ret "You can hardly ride ", (a) noun, "."; ];
  741.  
  742. Object -> horse "horse"
  743.   with short_name
  744.        [; if (self has general) print "winged horse";
  745.           else print "chestnut horse";
  746.           rtrue;
  747.        ],
  748.        parse_name
  749.        [ i j; if (self has general) j='winged'; else j=-1;
  750.           while (NextWord()==j or 'horse' or 'chestnut') i++;
  751.           return i;
  752.        ],
  753.        describe
  754.        [;  print_ret
  755.               "There is ", (a) self, " here, munching on a pile of oats.";
  756.        ],
  757.        before
  758.        [;  Cast: if (the_spell_was == bozbar_spell)
  759.                  {   give self general;
  760.                     "A pair of handsome brown wings suddenly appears on
  761.                      the horse's powerful shoulders.  The horse turns in a
  762.                      complete circle, a look of puzzlement on his face.";
  763.                  }
  764.                  if (the_spell_was == yomin_spell)
  765.                     "He is mainly thinking about oats.  Partly who you are
  766.                      and what you're up to, but mainly oats.";
  767.            Enter: <<Ride self>>;
  768.            Ride: if (horse hasnt general)
  769.                     "You ride around for a while, exercising the horse, but
  770.                      soon enough he tires of this and pointedly brings you
  771.                      back to the oats.  Obligingly you dismount and he
  772.                      begins grazing again.";
  773.  
  774.            print "You begin to ride north.  Then, slowly at first but with
  775.                   increasing sureness, the horse begins beating its powerful
  776.                   wings.  You rise majestically through the air, sailing
  777.                   gracefully across a chasm where the hills fall away. 
  778.                   The horse lands gently on the far side and deposits you,
  779.                   taking to the skies again.^";
  780.            PlayerTo(Edge); rtrue;
  781.        ],
  782.   has  animate;
  783.  
  784. Object -> oats "pile of oats"
  785.   with name "oats" "pile" "of",
  786.        before
  787.        [;  Examine, Search, LookUnder:
  788.                self.before=NULL;
  789.                move shiny_scroll to player; score=score+5;
  790.                itobj=shiny_scroll;
  791.                "Sifting through the oats, you find a shiny scroll!  Lucky
  792.                 you got to it before the horse did.  As you turn it over
  793.                 in your hands, it seems undamaged.";
  794.            Take:  "What would you want with all those oats?";
  795.        ],
  796.   has  scenery;
  797.  
  798. Scroll shiny_scroll "shiny scroll"
  799.   with name "shiny";
  800.  
  801. Spell -> bozbar_spell
  802.   with name "bozbar",
  803.        purpose "cause an animal to sprout wings",
  804.        magic
  805.        [;  if (second==0 || second hasnt animate)
  806.                "The spell dies away in vain.";
  807.            if (second==player)
  808.                "Your elbows twitch, but there is no other effect.";
  809.            print_ret "For a moment, ", (the) second,
  810.                " looks highly discomforted, but the moment passes.";
  811.        ],
  812.        unmagic
  813.        [;  if (second==0 || second hasnt animate)
  814.                "The spell dies away in vain.";
  815.            if (second==player) "What wings?";
  816.            if (second==horse && horse has general)
  817.            {   give horse ~general;
  818.                "The Enchanter giveth, and the Enchanter taketh away. 
  819.                 The horse looks disconsolate but returns to the oats.";
  820.            }
  821.            print_ret (The) second, " has no wings to lose.";
  822.        ];
  823.  
  824. ! ----------------------------------------------------------------------------
  825. !   The Chasm and the snake
  826. ! ----------------------------------------------------------------------------
  827.  
  828. Place Edge "Edge of Chasm"
  829.   with name "wide" "chasm" "road" "daffodils" "clump",
  830.        description
  831.           "The road ends suddenly at a wide chasm.  The road leads upward
  832.            to the north, and you can see it continuing on the southern side
  833.            of the chasm.",
  834.        u_to Up_Road, n_to Up_Road,
  835.        cant_go "The chasm is too perilous to approach.  The only safe way is
  836.                up and to the north.",
  837.        before
  838.        [;  Jump: deadflag = true;
  839.               "You jump bravely into the chasm, and plunge...
  840.                gracefully through the air.  (It gets a bit less noble and
  841.                airy after that.)";
  842.        ];
  843.  
  844. Object -> snake "hissing snake"
  845.   with name "hissing" "snake",
  846.        initial
  847.          "Lying in a tight coil at the edge of the chasm is a hissing snake.",
  848.        description
  849.          "It has some V-markings, some scaly parts, colours from grey to
  850.           reddish-brown. Is that any help?",
  851.        life
  852.        [; "The snake hisses angrily!"; ],
  853.        before
  854.        [;  Cast:
  855.                switch(the_spell_was)
  856.                {   urbzig_spell:
  857.                        remove self;
  858.                        snakes_cube.initial =
  859.                     "Beside a clump of daffodils is a featureless white cube.";
  860.                        "The snake is replaced by a clump of daffodils.";
  861.                    bozbar_spell:
  862.                        deadflag = true; remove self;
  863.                        snakes_cube.initial =
  864.                       "A featureless cube rests where the snake took off from.";
  865.                       "The snake is transformed into a huge, winged serpent,
  866.                        a dragon which bellows and leaps out into the chasm,
  867.                        backwinging furiously... and knocking you over the
  868.                        edge quite by accident.";
  869.                    yomin_spell:
  870.                       "Horrid reptilian thoughts insinuate their way into you.";
  871.                }
  872.            Take, Remove:
  873.               "The slipperiness of its skin is only one of many reasons
  874.                why this is ill-advised.";
  875.        ],
  876.   has  animate;
  877.  
  878. FeaturelessCube -> snakes_cube "cube"
  879.   with initial
  880.          "The snake appears to be curled around a featureless white cube.",
  881.        before
  882.        [; if (snake notin nothing) "The snake won't let you near that cube!";
  883.        ];
  884.  
  885. ! ----------------------------------------------------------------------------
  886. !   The crest of the hill; Icarus the tortoise; the chewed scroll
  887. ! ----------------------------------------------------------------------------
  888.  
  889. Place Up_Road "Crest of Hill"
  890.   with description
  891.           "The road crosses the top of a ridge here, sloping downwards to
  892.            the south and the northwest.  A track diverges to east.",
  893.        nw_to Cave_Mouth, s_to Edge, d_to Edge, e_to Track;
  894.  
  895. Object -> tortoise "tortoise"
  896.   with name "tortoise" "turtle",
  897.        initial "A tortoise ambles along the road, extremely slowly.",
  898.        life
  899.        [; "The tortoise (slowly) turns its neck to look at you (stupidly).";
  900.        ],
  901.        before
  902.        [; Cast: switch(the_spell_was)
  903.                 {   urbzig_spell:
  904.                        "Just how safe do you want your surroundings to be?";
  905.                     bozbar_spell:
  906.                         move chewed_scroll to parent(self); remove self;
  907.                         StartDaemon(self); score=score+5;
  908.                        "The tortoise seems to be incapable of expressing
  909.                         surprise, but is now soaring away high in the sky. 
  910.                         Something rather grubby is left behind.";
  911.                     yomin_spell:
  912.                        "For a moment you think there is nothing there, as you
  913.                         chew absentmindedly on a leaf.  But somewhere inside
  914.                         the tortoise is a sense of wonder at the amazing blue
  915.                         canopy of the sky.";
  916.                 }
  917.           Take, Remove:
  918.                "Your parents always warned you not to pick up casual
  919.                 acquaintances met on the road.";
  920.        ],
  921.        daemon
  922.        [ i; if (location ~= Up_Road or Track || random(6)~=1) rfalse;
  923.           if (random(4)==1 && self hasnt general)
  924.           {   move feather to location; give self general;
  925.               "^A tortoise-feather flutters to the ground before you!";
  926.           }
  927.           i=random(3);
  928.           switch(i)
  929.           {   1: print "^High in the sky,";
  930.               2: print "^Far above you,";
  931.               3: print "^Tiny in the blue sky,";
  932.           }
  933.           " a tortoise flaps across the sun.";
  934.        ],
  935.   has  animate;
  936.  
  937. Scroll torn_scroll "torn scroll"
  938.   with name "torn";
  939.  
  940. Spell -> lobal_spell
  941.   with name "lobal",
  942.        purpose "sharpen hearing",
  943.        magic
  944.        [;  if (second==0 || second hasnt animate)
  945.                "There is a loud bang in your ear, but no other effect.";
  946.            if (second==player)
  947.            {   if (hearing_good) "There is no further effect.";
  948.                hearing_good=1; StartTimer(self, 5);
  949.                "Nothing happens, possibly because those butterflies on the
  950.                 other side of the hill keep distracting you.";
  951.            }
  952.            print_ret (The) second,
  953.               " is no doubt grateful for the gift of sharper hearing.";
  954.        ],
  955.        unmagic
  956.        [;  if (second==0 || second hasnt animate)
  957.                "There is a brief silence, but no other effect.";
  958.            if (second==player) { StopTimer(self); hearing_good=0; "Pardon?"; }
  959.            print_ret (The) second,
  960.               " is no doubt grateful not to have to listen to you.";
  961.        ],
  962.        time_left 0,
  963.        time_out
  964.        [;  if (hearing_good)
  965.            {   hearing_good = false;
  966.                "^Those wretched butterflies finally shut up.";
  967.            }
  968.        ];
  969.  
  970. Scroll chewed_scroll "chewed scroll"
  971.   with initial "It looks as if the tortoise was eating something - once
  972.                 it might have been a scroll, but now it lies there,
  973.                 chewed up like a lettuce leaf.",
  974.        before
  975.        [;  Cast: if (the_spell_was == caskly_spell)
  976.                  {   move torn_scroll to parent(self);
  977.                      remove self; score=score+5;
  978.                      "Before your eyes, the scroll begins to repair itself,
  979.                       failing only at the very last tear.  Not quite perfect
  980.                       perhaps, but certainly a readable, if torn scroll.";
  981.                  }
  982.            Eat:  "~Eating your words~ is notoriously dangerous for a wizard.
  983.                   Rearranged in the stomach, a spell might do anything!";
  984.        ],
  985.   with name "chewed";
  986.  
  987. Object feather "tortoise feather"
  988.   with name "tortoise" "feather",
  989.        description
  990.           "Possibly your rarest, and also least valuable, possession.";
  991.         
  992. ! ----------------------------------------------------------------------------
  993. !   The cave mouth and the perfect sapphire
  994. ! ----------------------------------------------------------------------------
  995.  
  996. Place Cave_Mouth "Cave Mouth"
  997.   with name "gorse" "footpath" "cave" "mouth",
  998.        description
  999.           "This is a cave mouth, at one end of a road which winds southeast
  1000.            over rising ground.  The entrance west to the caves is a dark
  1001.            tunnel, and only a footpath runs further north, into gorse.",
  1002.        u_to Up_Road, se_to Up_Road, in_to Iron_Door, w_to Iron_Door,
  1003.        n_to Footpath;
  1004.  
  1005. Object -> Iron_Door "iron door"
  1006.   with name "iron" "door" "heavy",
  1007.        description "It just looks like an ordinary heavy iron door.",
  1008.        door_dir
  1009.        [; if (location==Cave_Mouth) return w_to; return e_to;
  1010.        ],
  1011.        door_to
  1012.        [; if (location==Cave_Mouth) return In_Cave;
  1013.           return Cave_Mouth;
  1014.        ],
  1015.        describe
  1016.        [; if (self has open) "^The iron door stands open.";
  1017.           if (self hasnt locked) "^The iron door is unlocked but shut.";
  1018.           "A heavy iron door bars the cave mouth.";
  1019.        ],
  1020.        found_in  In_Cave  Cave_Mouth
  1021.   has  static door openable locked lockable;
  1022.  
  1023. !  Cf. T. S. Eliot, "Burnt Norton" II:
  1024. !  (but see also Mallarme's sonnet from which Eliot borrowed the image)
  1025.  
  1026. Object -> sapphire "perfect sapphire"
  1027.   with name "perfect" "sapphire" "gemstone" "gem",
  1028.        initial "Clotted in the mud beside the door is a perfect sapphire.",
  1029.        before
  1030.        [;  Examine: remove self; move caskly_spell to memory;
  1031.                     players_book.learn_spell(caskly_spell);
  1032.                     caskly_spell.number=100;
  1033.                     "As you gaze into the perfect blue of the sapphire,
  1034.                      you feel your mind begin to reel.  Unable to bear
  1035.                      the naked sight of perfection, you look away, ashamed. 
  1036.                      As you do so, the sapphire cracks and wastes away to
  1037.                      thin hot dust.  But something remains, something in your
  1038.                      mind...";
  1039.        ];
  1040.  
  1041. Spell caskly_spell
  1042.   with name "caskly",
  1043.        purpose "cause perfection",
  1044.        magic
  1045.        [;  if (second==0) "Trying to make everything perfect was a little
  1046.                            too ambitious.";
  1047.            if (second==player) "Oh, don't be too hard on yourself.";
  1048.            if (second==helistars_book)
  1049.                "Your spell is not powerful enough to restore the lost pages.";
  1050.            print_ret (The) second, " looks pretty perfect as is.";
  1051.        ];
  1052.  
  1053. ! ----------------------------------------------------------------------------
  1054. !   Inside the Cave, the powerful urbzig spell and its consequences
  1055. ! ----------------------------------------------------------------------------
  1056.  
  1057. Place In_Cave "Inside Cave"
  1058.   with description
  1059.           "A wide but shallow cave not far inside the hill.  There is no
  1060.            obvious exit, except for the way you came in.",
  1061.        out_to
  1062.        [;  if (CoinsIn(left_pan)+CoinsIn(right_pan) < 6)
  1063.                "Something bars your way, and you hear
  1064.                 the scales jangling militantly.  You were trying to
  1065.                 steal its coins!";
  1066.            if (scales.number~=0) "Something bars your way, and you hear
  1067.                the scales jangle slightly with energy.";
  1068.            return Iron_Door;
  1069.        ],
  1070.        e_to
  1071.        [;  return self.out_to();
  1072.        ],
  1073.        cant_go "The only way is back ~out~ through the iron door.",
  1074.        after
  1075.        [;  Take: if (parent(noun)==left_pan or right_pan)
  1076.                      print_ret "Taken from ", (the) parent(noun), ".";
  1077.        ],
  1078.   has  ~light;
  1079.  
  1080. FeaturelessCube -> cave_cube "cube"
  1081.   with initial "Balanced on a rock formation is a featureless white cube.";
  1082.  
  1083. Object -> scales "pair of scales"
  1084.   with name "pair" "of" "scales" "pans", number 0,
  1085.        describe
  1086.        [;  print "^A fair-sized pair of scales hangs from a bracket in the
  1087.                   cave wall.  ";
  1088.            if (self.number==0)  "The scales are balanced.";
  1089.            if (self.number==1)  "The left-hand side is higher.";
  1090.            "The right-hand side is higher.";
  1091.        ],
  1092.        before
  1093.        [;  "There are left and right hand pans, which you should refer to
  1094.             individually.";
  1095.        ],
  1096.   has  static supporter;
  1097.  
  1098. Class  ScalePan
  1099.   with name "pan" "side" "tray",
  1100.        before
  1101.        [;  Receive:
  1102.            if (noun ofclass Scroll or Coin) rfalse;
  1103.            if (noun==feather) rfalse;
  1104.            "The pans gleam with what almost seems greed, and somehow they
  1105.             contrive to nudge your hand past them with your worthless and
  1106.             boring item.";
  1107.        ],
  1108.        after
  1109.        [ i j d w1 w2;  Receive, LetGo: i=scales.number;
  1110.            objectloop (j in left_pan) w1=w1 + WeightOf(j);
  1111.            objectloop (j in right_pan) w2=w2 + WeightOf(j);
  1112.            if (w1==w2) scales.number=0;
  1113.            if (w1 > w2) scales.number=-1;
  1114.            if (w1 < w2) scales.number=1;
  1115.            j=scales.number; d=(w2-w1)*(scales.number);
  1116.            if (j==i) rfalse;
  1117.            if (j==0) "The scales come into balance.";
  1118.            if (j==1) print "The left pan "; else print "The right pan ";
  1119.            if (d==1) "very slowly rises up.";
  1120.            "rises up.";
  1121.        ],
  1122.   has  supporter scenery;
  1123.  
  1124. [ WeightOf obj;
  1125.   if (obj==bronze_coin) return 2;
  1126.   if (obj ofclass Scroll || obj==feather) return 1;
  1127.   return 3;
  1128. ];
  1129.  
  1130. [ CoinsIn obj i c;
  1131.   objectloop (i in obj) if (i ofclass Coin) c++;
  1132.   return c;
  1133. ];
  1134.  
  1135. ScalePan -> right_pan "right pan" with name "right";
  1136. GoldCoin -> ->;
  1137. GoldCoin -> ->;
  1138. GoldCoin -> ->;
  1139.  
  1140. ScalePan -> left_pan "left pan" with name "left";
  1141. BronzeCoin -> -> bronze_coin;
  1142. GoldCoin -> ->;
  1143. GoldCoin -> ->;
  1144.  
  1145. Scroll -> -> crumpled_scroll "crumpled scroll"
  1146.   with name "crumpled";
  1147. Spell  -> -> -> urbzig_spell
  1148.   with name "urbzig",
  1149.        purpose "turn a dangerous object into a harmless one",
  1150.        magic
  1151.        [;  if (second==0) "The spell fizzles away.";
  1152.            if (second==player) "It's a matter of opinion, isn't it?";
  1153.            if (second==helistars_book or mace || second ofclass FeaturelessCube)
  1154.            {   CDefArt(second); remove second;
  1155.                if (second==mace && cyclops in location)
  1156.                {   remove cyclops; move eye_cube to location;
  1157.                    " turns into a featureless white cube just as the cyclops
  1158.                     was about to hit you with it.  Mightily embarrassed
  1159.                     by this, he drops the cube and runs off!";
  1160.                }
  1161.                print " turns into a moth and flutters away.^";
  1162.                rtrue;
  1163.            }
  1164.            print_ret "Nothing obvious happens.  Perhaps ", (the) second,
  1165.                      " isn't so very dangerous after all.";
  1166.        ],
  1167.        unmagic
  1168.        [;  if (second==0) "The spell fizzles away.";
  1169.            if (second==player) "It's a matter of opinion, isn't it?";
  1170.            if (second has static || second has scenery)
  1171.            {   print_ret "Your spell is too weak for something quite as
  1172.                           monumentally harmless as ", (the) second, ".";
  1173.            }
  1174.            if (second==helistars_book or snake or cyclops or mace
  1175.                || second ofclass FeaturelessCube)
  1176.                "Nothing obvious happens.";
  1177.            if (second in player)
  1178.            {   remove second; deadflag = true;
  1179.                "Suddenly, a tarantula races up your arm to your throat! 
  1180.                 Perhaps it was unwise to gizbru something you were
  1181.                 actually holding.";
  1182.            }
  1183.            if (cyclops has general)
  1184.                "Nothing happens.  Perhaps that's just as well,
  1185.                 after the last time.";
  1186.            move cyclops to location;
  1187.            remove second; give cyclops general; StartTimer(cyclops, 5);
  1188.            print_ret (The) second, " is replaced by a buck-toothed cyclops
  1189.                 wielding a mace!";
  1190.        ];
  1191.  
  1192. Object cyclops "buck-toothed cyclops"
  1193.   with name "buck" "toothed" "buck-toothed" "cyclops",
  1194.        initial "A huge buck-toothed cyclops menaces you, armed with a
  1195.                 heavy mace!",
  1196.        before
  1197.        [;  Cast: if (the_spell_was == bozbar_spell)
  1198.                      "Does the term ~death wish~ mean anything to you?";
  1199.                  if (the_spell_was == urbzig_spell)
  1200.                      "The cyclops bellows with glee as your spell has
  1201.                       no effect.  (After all, he wouldn't be ~dangerous~ if
  1202.                       an urbzig spell worked on him, would he?)";
  1203.        ],
  1204.        life [; "He roars incoherently, swinging the mace!"; ],
  1205.        time_left 0,
  1206.        time_out
  1207.        [;  if (self notin location)
  1208.            {   remove self; rtrue;
  1209.            }
  1210.            deadflag = true; remove mace; remove cyclops;
  1211.            "Feeling that he's given you quite long enough to explain why
  1212.             you made such a mess of his life, he swings the great mace
  1213.             maniacally down on you!";
  1214.        ],
  1215.        each_turn
  1216.        [ i; i=random(4); if (i==1) "^The cyclops leaps and bellows!";
  1217.             if (i==2)
  1218.               "^Whirling the mace, the cyclops jabbers at you incoherently.";
  1219.             if (i==3)
  1220.               "^The cyclops is losing patience (the appropriate cyclops
  1221.                 word is untranslatable into English, but approximately means
  1222.                 ~forbearance in not smashing all nearby skulls~).";
  1223.             "^The cyclops jabs you with the mace, almost breaking your rib.";
  1224.        ],
  1225.   has  animate transparent;
  1226.  
  1227. Object -> mace "mace"
  1228.   with name "heavy" "mace" "axe",
  1229.        description "It looks much too heavy for you to even lift.";
  1230.  
  1231. FeaturelessCube -> eye_cube "cube"
  1232.   with initial
  1233.          "A featureless white cube lies where the cyclops dropped it.";
  1234.  
  1235. ! ----------------------------------------------------------------------------
  1236. !   The Footpath and the carpet
  1237. ! ----------------------------------------------------------------------------
  1238.  
  1239. Place Footpath "Gorse Bushes"
  1240.   with description
  1241.            "The footpath from the cave mouth runs into dense, impenetrable
  1242.             gorse bushes.  Perhaps it wasn't so much a footpath as a rill
  1243.             in the earth where roots wouldn't take; anyway, there's no way
  1244.             but back south.",
  1245.        s_to Cave_Mouth;
  1246.  
  1247. Object -> carpet "beautiful red carpet"
  1248.   with name "beautiful" "magic" "red" "carpet",
  1249.        initial
  1250.           "Slung over one of the gorse bushes is a beautiful red carpet.",
  1251.        description
  1252.           "This is a carpet of unusual design. It is red, beautifully woven
  1253.            and bears a pattern of cubes.",
  1254.        before
  1255.        [ i;  Receive:
  1256.                  if (self notin location || self hasnt moved)
  1257.                      "Not until the carpet's on the ground, you can't.";
  1258.            Ride: <<Enter self>>;
  1259.            Enter:
  1260.                  if (self notin location || self hasnt moved)
  1261.                      "Not until the carpet's on the ground, you can't.";
  1262.                  if (location==Balance_Room)
  1263.                      "Mysteriously, the carpet rucks and pulls until you're
  1264.                       thrown off.  It settles back on the white floor with a
  1265.                       contented sigh.";
  1266.                  if (location==In_Cave)
  1267.                      "The carpet rises suddenly, crashing into the roof of
  1268.                       the cave and throwing you back off again.  Painfully.";
  1269.                  if (location==Bazaar) i=Up_Road; else i=Bazaar;
  1270.                  print "The carpet rises suddenly into the fluffy white
  1271.                         clouds, and after a headlong journey deposits you...^";
  1272.                  move self to i;
  1273.                  PlayerTo(i,1); move player to self; <<Look>>;
  1274.            Take: if (player in self) "Not while you're on it!";
  1275.                  for (i=child(self):i~=0:i=child(self))
  1276.                  {   move i to location;
  1277.                      print "(Dislodging ", (the) i, ")^";
  1278.                  }
  1279.        ],
  1280.   has  supporter enterable;
  1281.  
  1282. ! ----------------------------------------------------------------------------
  1283. !   A Bazaar Lottery
  1284. ! ----------------------------------------------------------------------------
  1285.  
  1286. Global last_called = 1;
  1287. Global explicit_flag = 0;
  1288. Global tickets_taken = 0;
  1289.  
  1290. Class Ticket(6)
  1291.   with number -1, name "ticket",
  1292.        description
  1293.        [;  if (self.number==2306) "It is labelled ~First Prize~!";
  1294.            if (self.number==5802) "It is labelled ~Nineteenth Prize~.";
  1295.            "~You lose,~ says the ticket, with a smily face.  ~Try again!~";
  1296.        ],
  1297.        short_name
  1298.        [;  if (self.number==-1) rfalse;
  1299.            print "lottery ticket ", self.number; rtrue;
  1300.        ],
  1301.        parse_name
  1302.        [ i j w;
  1303.            i=0;
  1304.            if (NextWord()=='lottery') i++; else wn--;
  1305.            if (NextWord()=='tickets')
  1306.            {   parser_action=##PluralFound; return i+1; } else wn--;
  1307.            if (NextWord()~='ticket') return 0;
  1308.            i++;
  1309.            w=TryNumber(wn);
  1310.            if (w==-1000) { explicit_flag = false; return i; }
  1311.            if (w==0) return 0;
  1312.            if (self.number==-1)
  1313.            {   objectloop(j ofclass Ticket)
  1314.                    if (w == j.number) return 0;
  1315.            }
  1316.            else
  1317.            {   if (self.number~=w) return 0;
  1318.            }
  1319.            i++; last_called = w; explicit_flag = true; return i;
  1320.        ],
  1321.        before
  1322.        [;  Examine:
  1323.                if (self in board)
  1324.                   "It would be cheating to see what's written on the curled up
  1325.                    tickets still in the board.";
  1326.            Cast: "~Get outta here, bub!~, the barker says, disgusted.";
  1327.        ];
  1328.  
  1329. Place Bazaar "Crowded Bazaar"
  1330.   with description
  1331.            "This is a crowded, noisy bazaar.  Directly in front of you is
  1332.             a lottery!  But the contemptuous-looking barker is doing a
  1333.             very poor trade: hardly anyone wants his first prize, the
  1334.             big cuddly toy elephant, or even his nineteenth prize, a
  1335.             featureless white cube.",
  1336.        each_turn
  1337.        [;   switch(random(4))
  1338.             {   1: "^~Roll up!  Roll up!  One silver piece for three goes!~";
  1339.                 2: "^~Come on, then!  Just a silver coin gets you three!~";
  1340.                 3: "^~Think what you could win, all for one silver coin!~";
  1341.                 4: "^~This could be your lucky day!~";
  1342.             }
  1343.        ],
  1344.        before
  1345.        [;   Learn:
  1346.                 "~None of that!~ snaps the barker angrily, putting you off
  1347.                  your study habits.  He mutters about ~Enchanter cheats~,
  1348.                  but under the circumstances you decide to let the insult
  1349.                  pass.";
  1350.        ],
  1351.        cant_go "Everywhere, the crowds of jabbering natives block your way
  1352.            to all the good stalls.  In fact, the only one you can get at is
  1353.            this dismal lottery.";
  1354.  
  1355. Object -> board "lottery board"
  1356.   with credit 0,
  1357.        name "board" "lottery" "holes",
  1358.        description
  1359.            "There are a hundred holes each way, making, um, let's see, yes,
  1360.             ten thousand tickets in all. Still, there are nineteen prizes,
  1361.             so your odds must be, oh, well, not too awful anyway.",
  1362.        before
  1363.        [ i; LetGo:
  1364.                 if (self.credit == 0)
  1365.                    "The barker stabs you in the chest with
  1366.                     his finger.  ~That's a silver coin to you, bub!~";
  1367.  
  1368.                 if (explicit_flag)
  1369.                 {   objectloop (i ofclass Ticket)
  1370.                         if (last_called == i.number)
  1371.                             "That ticket's already taken.";
  1372.                 }
  1373.                 else
  1374.                 {   .RandomChoice;
  1375.                     last_called = random(10000);
  1376.                     objectloop (i ofclass Ticket)
  1377.                         if (last_called == i.number)
  1378.                             jump RandomChoice;
  1379.                 }
  1380.  
  1381.                 tickets_taken++;
  1382.                 self.credit--;
  1383.  
  1384.                 i = Ticket.create();
  1385.                 if (i == 0)
  1386.                    "The barker looks metaphysically embarrassed. ~Um,
  1387.                     Inform's object creation system seems not to have worked.~";
  1388.  
  1389.                 i.number = last_called; itobj = i;
  1390.  
  1391.                 move i to player; give i moved proper;
  1392.                 if (explicit_flag==0)
  1393.                     print "Randomly picking from the ", 10001-tickets_taken,
  1394.                           " numbered holes with tickets in, you ";
  1395.                     else print "You ";
  1396.                 print_ret "take ", (the) i, " out of the board.";
  1397.  
  1398.             Examine: ;
  1399.             Receive:
  1400.                 if (noun ofclass Ticket)
  1401.                    "~No changes of mind, that's your ticket now!  Give it to
  1402.                      me if you want to play it.~";
  1403.                 <<Push self>>;
  1404.             default:
  1405.                 "The barker is burly, and won't let you
  1406.                  tamper with the board.";
  1407.        ],
  1408.        initial
  1409.            "Behind the barker is a huge drilled board, and inside each little
  1410.             numbered hole is a rolled-up lottery ticket."
  1411.   has  static container open;
  1412.  
  1413. Ticket -> -> ticket_in_board "rolled-up ticket from the board"
  1414.   with article "a";
  1415.  
  1416. Object -> barker "barker"
  1417.   with name "barker" "burly" "man",
  1418.        number 0,
  1419.        description
  1420.            "A boxer gone to seed who failed as a magician all down the
  1421.             coast, that'd be your guess.",
  1422.        life
  1423.        [;  Attack, Kiss: "No way.  He must weigh twice what you do.";
  1424.            Ask:  switch(noun)
  1425.                  {   'prize', 'prizes':
  1426.                          "~Just one silver coin and a prize could be yours!~";
  1427.                      'white', 'featureless', 'cube':
  1428.                          "He blows the dust off it.  ~Genuine antique, that.~";
  1429.                      'elephant', 'toy', 'cuddly':
  1430.                          "~Good quality merchandise,~ he says, in a way that
  1431.                           suggests he can only spell one of those three words.";
  1432.                      'ticket', 'tickets', 'lottery':
  1433.                          "~Three tickets for one silver coin!~";
  1434.                      default: "~Just play the game, bub.~";
  1435.                  }
  1436.            Order, Answer: "The barker glowers at you.";
  1437.            Give: if (noun ofclass Ticket)
  1438.                  {   remove noun;
  1439.                      if (noun.number==2306)
  1440.                      {   move elephant to player; give elephant moved;
  1441.                          remove pelephant;
  1442.                          Bazaar.description =
  1443.            "This is a crowded, noisy bazaar.  Directly in front of you is
  1444.             the lottery!";
  1445.                          "With very bad grace, the barker shoves the
  1446.                           cuddly toy elephant into your arms.";
  1447.                      }
  1448.                      if (noun.number==5802)
  1449.                      {   move barker_cube to player; give barker_cube moved;
  1450.                          remove pcube;
  1451.                          Bazaar.description =
  1452.            "This is a crowded, noisy bazaar.  Directly in front of you is
  1453.             the lottery!";
  1454.                          score=score+5;
  1455.                          "With concealed relief, the barker shoves the
  1456.                           featureless white cube into your hands.";
  1457.                      }
  1458.                      "~Bad luck!  You lose!~";
  1459.                  }
  1460.                  if (self.number==2) "~You've had enough goes already!~ he
  1461.                      growls.  No wonder trade is bad.";
  1462.                  if (~~(noun ofclass Coin))
  1463.                      "~What do you call that? One silver coin to play!~";
  1464.                  if ((noun.&name)-->0 == 'bronze')
  1465.                      "~Bronze!  Not a chance, sunshine.~";
  1466.                  remove noun;
  1467.                  board.credit = board.credit + 3;
  1468.                  self.number++;
  1469.                  if ((noun.&name)-->0 == 'gold')
  1470.                      "Gleefully the barker snatches the gold coin. ~Sorry
  1471.                       bub, no change. Business is slack today!~";
  1472.                  "Grudgingly the barker takes the silver coin and stands
  1473.                   back to let you at the board, arms folded.";
  1474.        ],
  1475.        before
  1476.        [;  Cast: switch(the_spell_was)
  1477.                  {   bozbar_spell:
  1478.                         "He's not that much of an animal.";
  1479.                      lobal_spell:
  1480.                         "His problem is listening, not hearing.";
  1481.                      caskly_spell:
  1482.                         "For a moment his hair seems to comb itself. 
  1483.                          Irritated, he ruffles it again, and the spell dies
  1484.                          an ignominious death.";
  1485.                      yomin_spell:
  1486.                          if (elephant has moved || barker_cube has moved)
  1487.                          "The barker's mind is a heap of grumbles about lost
  1488.                           prizes and scrawny Enchanters.";
  1489.                          if (self hasnt general)
  1490.                          {   give self general;
  1491.                             "~Hope that scrawny Enchanter doesn't pick 2306!~
  1492.                              thinks the barker (slowly).";
  1493.                          }
  1494.                          "~If that mark does win, hope it's only worthless
  1495.                           old 5802,~ ponders the barker.";
  1496.                  }
  1497.        ],
  1498.   has  animate scenery;
  1499.  
  1500. Object -> prizes "prizes"
  1501.   with name "prize" "prizes",
  1502.        before [; "~Hands off those prizes!~"; ],
  1503.   has  scenery;
  1504.  
  1505. Object -> pelephant "prize elephant"
  1506.   with name "prize" "elephant" "cuddly" "toy",
  1507.        description "Pink, cuddly, toy, elephant.  Says it all, really.",
  1508.        before [; Examine: ; default: "~Hands off those prizes!~"; ],
  1509.   has  scenery;
  1510.        
  1511. Object -> pcube "prize cube"
  1512.   with name "prize" "featureless" "white" "cube",
  1513.        description "Wouldn't you like to win it?",
  1514.        before [; Examine: ; default: "~Hands off those prizes!~"; ],
  1515.   has  scenery;
  1516.  
  1517. Object elephant "cuddly toy elephant"
  1518.   with name "cuddly" "toy" "elephant",
  1519.        description "Pink, cuddly, toy, elephant.  Says it all, really.",
  1520.        before
  1521.        [;  Cast: if (the_spell_was == bozbar_spell)
  1522.                      "Let me get this straight.  You, the enchanter who
  1523.                       defeated Krill, the head of the Borphee Guild
  1524.                       himself...  are attempting to grow wings on a pink
  1525.                       cuddly elephant?";
  1526.                  if (the_spell_was == yomin_spell) "Woolly.";
  1527.        ];
  1528.  
  1529. FeaturelessCube barker_cube "cube";
  1530.  
  1531. ! ----------------------------------------------------------------------------
  1532. !   The spells in Helistar's grimoire
  1533. ! ----------------------------------------------------------------------------
  1534.  
  1535. Spell lleps_spell
  1536.   with name "lleps",
  1537.        purpose "reverse effect of memorised spell",
  1538.        magic
  1539.        [;   if (second==0 || second notin memory)
  1540.                 "The spell backfires, painfully.";
  1541.             if (second.number==100)
  1542.                 "You know that spell too well for your mind to be able
  1543.                  to accept the change.";
  1544.             if (second has reversed) give second ~reversed;
  1545.             else give second reversed;
  1546.             if (second==lleps_spell)
  1547.             {    memory.forget_spell(second);
  1548.                 "Your mind wrenches as the two lleps spells
  1549.                  cancel each other out, leaving only a sensation
  1550.                  quite like a hangover.";
  1551.             }
  1552.             print_ret "Your mind wrenches as ", (the) second,
  1553.                       " reverses itself.";
  1554.        ],
  1555.        unmagic
  1556.        [;   return self.magic();         !  The reverse of "lleps" is "lleps"
  1557.        ];
  1558.  
  1559. Spell mortin_spell
  1560.   with name "mortin",
  1561.        purpose "cause immediate death of caster",
  1562.        magic
  1563.        [;   deadflag = true;
  1564.             "You really can't fault Helistar on this one.  Death is
  1565.              absolutely immediate, like a sudden blackout curtain...";
  1566.        ],
  1567.        unmagic
  1568.        [;   prepared_flag = true;
  1569.             "Nothing quite happens... and yet you feel enormously more
  1570.              confident as you go about this dangerous world.";
  1571.        ];
  1572.  
  1573. ! ----------------------------------------------------------------------------
  1574. !   Death and the Boneyard
  1575. ! ----------------------------------------------------------------------------
  1576.  
  1577. [ AfterLife;
  1578.   if (~~prepared_flag) rfalse;
  1579.   
  1580.   if (player in Balance_Room)
  1581.       "^^Your foresight in preparing a resurrection was wasted.  The
  1582.          tangled magic of the Balance Room coiled around your puny
  1583.          enchantment like a constricting serpent.";
  1584.  
  1585.   prepared_flag = false; deadflag = false; hearing_good = false;
  1586.  
  1587.   if (memory.capacity >= 2) memory.capacity--;
  1588.  
  1589.   while (child(player)~=0) move child(player) to parent(player);
  1590.   move players_book to player;
  1591.  
  1592.   print "^^With great foresight you prepared yourself for resurrection... 
  1593.            Your mind feels a little weaker, but at least you're alive.^";
  1594.   PlayerTo(Boneyard);
  1595. ];
  1596.  
  1597. Place Boneyard "Boneyard"
  1598.   with name "bones" "blades" "shoulder" "skulls",
  1599.        description
  1600.           "This is a room of bones.  Shoulder blades make up the floor,
  1601.            skulls the walls and leg-bones the door frames. The west exit
  1602.            leads into darkness, but the doorway to the north opens onto a
  1603.            seemingly normal scene.",
  1604.        n_to
  1605.        [;  if (scales.number ~= 0) return In_Cave;
  1606.            return Grasslands;
  1607.        ],
  1608.        w_to "Some magical force blocks your way, as though that doorway
  1609.              led into adventures from your past which you cannot rejoin now.",
  1610.        before
  1611.        [;  Examine, Search:
  1612.                if (noun==w_obj) "You can make out nothing to the west.";
  1613.        ];
  1614.  
  1615. Scroll -> worthless_scroll "worthless scroll"
  1616.   with initial "You are almost treading on a worthless scroll.",
  1617.        name "worthless";
  1618.  
  1619. Spell -> -> filfre_spell
  1620.   with name "filfre",
  1621.        purpose "produce gratuitous fireworks",
  1622.        magic
  1623.        [;    if (self hasnt scored) { score++; give self scored; }
  1624.             "A brief shower of gratuitous fireworks spells out:
  1625.            ^^The masterly Enchanter trilogy was written by Marc Blank,
  1626.              Dave Lebling and Steve Meretzky.";
  1627.        ],
  1628.        unmagic
  1629.        [;   "A lengthy shower of artistically justified fireworks spells out:
  1630.            ^^The masterly Enchanter trilogy was written by Jane Austen,
  1631.              Emily Bronte and Edgar Allen Poe.";
  1632.        ];
  1633.  
  1634. ! ----------------------------------------------------------------------------
  1635. !   The Cubical Temple
  1636. ! ----------------------------------------------------------------------------
  1637.  
  1638. Place Track "Track, outside Temple"
  1639.   with description
  1640.           "This is the end of a long track winding through desolate hills,
  1641.            which runs back west up to the ridge.",
  1642.        before
  1643.        [;   Listen:
  1644.                 if (~~hearing_good) "The chanting is too quiet to make out.";
  1645.                 "The endlessly repeating threnody of the monks tells of
  1646.                  the legend of one who will some day enlighten their order,
  1647.                  and so be taken up to a higher plane.  He (or she,
  1648.                  presumably) is known as The Four-Cubed One.";
  1649.        ],
  1650.        w_to Up_Road, u_to Up_Road;
  1651.  
  1652. Object -> Temple "cubical Temple"
  1653.   with name "temple" "cubical" "cube" "enormous",
  1654.        before
  1655.        [ i j;
  1656.          Enter: "The Temple is featureless and unbroken.  Perhaps the top
  1657.                  is open, because the sound must come from somewhere...
  1658.                  but you wouldn't bet on it.";
  1659.          Cast:   switch(the_spell_was)
  1660.                  {   rezrov_spell:
  1661.                         "The huge temple remains impassive at your relatively
  1662.                          puny enchantment.";
  1663.                      frotz_spell:
  1664.                          objectloop (i in player)
  1665.                              if (i ofclass FeaturelessCube) j++;
  1666.                          if (j==0)
  1667.                              "The temple shakes, but then is still again.";
  1668.                          if (j<4) "The temple shakes!  White light plays
  1669.                              over your hands and possessions, but then all is
  1670.                              still again.";
  1671.                          print "The temple shakes and white light bathes you. 
  1672.                              Smoothly it unfolds itself in a four-dimensional
  1673.                              way your senses can barely comprehend.  All you
  1674.                              know is that when it is over,
  1675.                              you find yourself in...^";
  1676.                          hearing_good = false; score=score+5;
  1677.                          PlayerTo(Balance_Room); rtrue;
  1678.                  }
  1679.        ],
  1680.        describe
  1681.        [;   print "^You stand outside an enormous temple in the shape of a
  1682.                    perfect, featureless white cube, four hundred feet on a
  1683.                    side.  From somewhere within you hear the ";
  1684.             if (hearing_good) print "bellowing noise";
  1685.             else print "tiny sound";
  1686.             " of the monks chanting.";
  1687.        ],
  1688.        description
  1689.            "It's much like every other gigantic temple in the shape of a
  1690.             featureless white cube you've ever seen.  No obvious way in.",
  1691.   has  static;
  1692.  
  1693. ! ----------------------------------------------------------------------------
  1694. !   Inside the Temple
  1695. ! ----------------------------------------------------------------------------
  1696.  
  1697. Place Balance_Room "Balance Room"
  1698.   with description
  1699.            "This seems to be the inside of a featureless white cube, forty
  1700.             feet on a side.  The air is stale and there is no exit.";
  1701.  
  1702. Object -> balance_meter "image of the scales"
  1703.   with name "image" "scales" "of" "pair", article "the",
  1704.        initial "The image of a pair of scales hangs high in the air.  One
  1705.                 pan is much lower than the other.",
  1706.        before
  1707.        [; "It's only an image.";
  1708.        ],
  1709.   has  static;
  1710.  
  1711. Object -> dusty_podium "dusty podium"
  1712.   with name "podium" "dusty" "cobwebs" "cobwebbed",
  1713.        initial "Far below the scales, in the centre of the ~floor~, is a
  1714.                 predictably-shaped podium, but it is so dusty and
  1715.                 cobwebbed that you can't see what it once was.",
  1716.        before
  1717.        [;  Cast: if (the_spell_was == caskly_spell)
  1718.                     "Nice try, but it is protected from enchantment.";
  1719.                 "However dusty it is, the podium is still protected from
  1720.                  casual enchantment.";
  1721.            Rub:  remove self; move balance_key to Balance_Room;
  1722.                  itobj = balance_key;
  1723.                 "No substitute for old-fashioned hard work, sometimes,
  1724.                  and after much patient (sneezy) scrubbing, the podium
  1725.                  appears in its true white glory.  Set into it are four
  1726.                  sockets, arranged in a two by two square.";
  1727.        ],
  1728.   has  static;
  1729.  
  1730. Object balance_key "podium"
  1731.   with name "podium" "pedestal" "platform" "cubical",
  1732.        description "As predicted, it is cubical.",
  1733.        initial "Far below the scales, in the centre of the ~floor~, is a
  1734.                 predictably-shaped podium.  Set into it are four sockets,
  1735.                 arranged in a two by two square.",
  1736.   has  static supporter;
  1737.  
  1738. Object -> sockets "two by two square"
  1739.   with name "square" "two" "by" "two",
  1740.        before
  1741.        [ i;  if (action~=##Examine || number_filled==0)
  1742.               "You'll have to say which socket you mean. 
  1743.                (Let's call them ~top left~, ~bottom right~ and so on.)";
  1744.            objectloop (i in self)
  1745.            {   print (The) i;
  1746.                if (child(i)==0) print " is empty.^";
  1747.                else { print " contains ", (a) child(i), ".^"; }
  1748.            }
  1749.            rtrue;
  1750.        ],
  1751.   has  static;
  1752.  
  1753. Class Socket
  1754.   with name "socket", article "the",
  1755.        before
  1756.        [;  Cast:  "The sockets are proof against magic.";
  1757.            Examine: print (The) self, ", cubical and slightly more
  1758.                     than four inches on a side, is decorated with ",
  1759.                     (string) self.description;
  1760.                     if (child(self) == nothing) ".";
  1761.                     print_ret ", and contains ", (a) child(self), ".";
  1762.            Receive: if (~~(noun ofclass FeaturelessCube))
  1763.                        "The socket rejects that.";
  1764.                     if (child(self) ~= nothing)
  1765.                        "There is already a cube in that socket.";
  1766.        ],
  1767.        after
  1768.        [;  LetGo:  number_filled--;
  1769.                    "With much struggle, you manage to pull the cube away.";
  1770.            Receive: number_filled++;
  1771.            if (number_filled==4)
  1772.            {   if (snakes_cube in bl_socket
  1773.                    && barker_cube in ul_socket
  1774.                    && cave_cube in br_socket
  1775.                    && eye_cube in ur_socket)
  1776.                {   deadflag=2; score=score+5;
  1777.                   "As you place the final cube into the sockets, you feel
  1778.                    imbued with celestial wisdom (more so than usually). 
  1779.                    You find yourself growing to the height of the cube, so
  1780.                    that you pull the balances back level by hand, and then
  1781.                    you grow still further, out of the temple until it is but
  1782.                    a cube in your hand, and you are a giant towering over
  1783.                    the land.
  1784.                  ^^Then, of course, you wake up, glumly realising it's time
  1785.                    to go to your job at the new Borphee Laboratories and
  1786.                    all those Wheatstone bridge experiments.  But at least
  1787.                    you can dream about the old days.";
  1788.                }
  1789.               "The sockets are all full now, but that doesn't mean
  1790.                anything's happened.";
  1791.            }
  1792.           "The cube is a predictably perfect fit in the socket.";
  1793.        ],
  1794.   has  static container open;
  1795.  
  1796. Socket -> bl_socket "bottom left socket"
  1797.   with name "bottom" "left" "serpent",
  1798.        description "a serpent";
  1799.  
  1800. Socket -> ul_socket "top left socket"
  1801.   with name "top" "left" "bazaar",
  1802.        description "a scene in a bazaar";
  1803.  
  1804. Socket -> br_socket "bottom right socket"
  1805.   with name "bottom" "right" "cave",
  1806.        description "an engraving of a rocky cave";
  1807.  
  1808. Socket -> ur_socket "top right socket"
  1809.   with name "top" "right" "eye",
  1810.        description "an eye";
  1811.  
  1812. ! ----------------------------------------------------------------------------
  1813. !   That's all of the object definitions: just a little code and grammar left
  1814. ! ----------------------------------------------------------------------------
  1815.  
  1816. [ Initialise;
  1817.  
  1818.   location = Hut;
  1819.   move burin to player;
  1820.   move players_coin to player;
  1821.   move players_book to player;
  1822.  
  1823.   thedark.description =
  1824.       "It is pitch black.  You are likely to be eaten by a grue.";
  1825.   ! (In fact you are stone-cold certain not to be, but never mind.)
  1826.  
  1827.   players_book.learn_spell(gnusto_spell);
  1828.   players_book.learn_spell(frotz_spell);
  1829.   players_book.learn_spell(yomin_spell);
  1830.   players_book.learn_spell(rezrov_spell);
  1831.  
  1832.   helistars_book.learn_spell(frotz_spell);
  1833.   helistars_book.learn_spell(lleps_spell);
  1834.   helistars_book.learn_spell(mortin_spell);
  1835.  
  1836.   give gnusto_spell known_about;
  1837.  
  1838.  "^^^^^[Welcome to a short story called ~Balances~, one of the example
  1839.        games for the Inform design system. Some people may recognise the
  1840.        setting, but others might like to type ~how do spells work~ -
  1841.        the game responds to a few such questions.]
  1842.      ^^You feel a little confused as to how you got here.  Something
  1843.        to do with Helistar!  That's right, and how the world is so far
  1844.        off balance nowadays, after the Great Change.^^";
  1845. ];
  1846.  
  1847. [ PrintRank;
  1848.   print ", earning you the rank of ";
  1849.   if (score >= 50)  "Scientist.";
  1850.   if (score >= 40)  "Spellbreaker.";
  1851.   if (score >= 30)  "Sorcerer.";
  1852.   if (score >= 20)  "Enchanter.";
  1853.   if (score >= 10)  "novice Enchanter.";
  1854.   "lost dreamer.";
  1855. ];
  1856.  
  1857. [ DiagnoseSub;
  1858.   switch(memory.capacity)
  1859.   {   5: "You feel fine, and your memory is unimpaired.";
  1860.       4: "You feel shaky after your brush with death, but your mental
  1861.           faculties seem sound.";
  1862.       3: "For someone who has died twice, you're in reasonable shape.";
  1863.   }
  1864.   "How many times have you died now?  Your memory isn't what it was.";
  1865. ];
  1866.  
  1867. ! ----------------------------------------------------------------------------
  1868. !   Grammar extensions needed by the spell-casting and cube-writing rules:
  1869. ! ----------------------------------------------------------------------------
  1870.  
  1871. Include "Grammar";
  1872.  
  1873. [ AnyWord; from_char=0; to_char=0; the_named_word=wn++; return burin; ];
  1874.  
  1875. [ QuotedText i j f;
  1876.    i = WordAddress(wn++); i=i-buffer;
  1877.    if (buffer->i=='"')
  1878.    {   for (j=i+1:j<=(buffer->1)+1:j++)
  1879.            if (buffer->j=='"') f=j;
  1880.        if (f==0) return -1;
  1881.        from_char = i+1; to_char=f-1;
  1882.        if (from_char>to_char) return -1;
  1883.        while (buffer+f > WordAddress(wn)) wn++; wn++;
  1884.        return burin;
  1885.    }
  1886.    return -1;
  1887. ];
  1888.  
  1889. Verb "write" "scribe"
  1890.                 * AnyWord "on" held              -> WriteOn
  1891.                 * QuotedText "on" held           -> WriteOn;
  1892. Verb "copy"     * scope=CopyableSpell "to" noun  -> CopyTo;
  1893. Verb "who" "what" "how"
  1894.                 * "do"  scope=Topic              -> Query
  1895.                 * "is"  scope=Topic              -> Query
  1896.                 * "was" scope=Topic              -> Query;
  1897. Verb "spells" "memory"
  1898.                 *                                -> Spells;
  1899. Verb "learn" "memorise" "memorize"
  1900.                 * scope=ReadableSpell            -> Learn;
  1901. Extend "examine" first
  1902.                 * scope=ReadableSpell            -> Examine;
  1903. Verb "c,cast"
  1904.                 *                                -> CastOne
  1905.                 * noun                           -> CastOne;
  1906. Verb "cast"
  1907.                 * is_spell                       -> Cast
  1908.                 * is_spell "at" noun             -> Cast
  1909.                 * is_spell "on" noun             -> Cast;
  1910. Verb "diagnose" "health"
  1911.                 *                                -> Diagnose;
  1912.  
  1913. ! ----------------------------------------------------------------------------
  1914. !   And one for the game itself.
  1915. ! ----------------------------------------------------------------------------
  1916.  
  1917. Verb "ride" "mount" "straddle"
  1918.                 * creature                       -> Ride
  1919.                 * noun                           -> Enter;
  1920. Verb "flip" "toss" * is_coin                     -> TossCoin;
  1921. ! ----------------------------------------------------------------------------
  1922.